import 'package:flutter_html/src/builtins/image_builtin.dart';
import 'package:meta/meta.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_test/flutter_test.dart';

import 'golden_test.dart';

void main() {
  group("asset uri matcher", () {
    //TODO replace when ImageMatcherExtension is written
    matcher(ExtensionContext context) {
      return context.elementName == "img" &&
          (context.attributes['src']?.startsWith("asset:") ?? false);
    }

    testImgSrcMatcher(
      "matches a full asset: uri",
      matcher,
      imgSrc: 'asset:some/asset.png',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "matches asset: schema without path",
      matcher,
      imgSrc: 'asset:',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "doesn't match literal host 'asset'",
      matcher,
      imgSrc: 'asset/faulty.path',
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match null",
      matcher,
      imgSrc: null,
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match empty",
      matcher,
      imgSrc: '',
      shouldMatch: false,
    );
  });
  group("default network source matcher", () {
    //TODO replace when ImageMatcherExtension is written
    matcher(ExtensionContext context) {
      return context.elementName == "img" &&
          ((context.attributes['src']?.startsWith("http:") ?? false) ||
              (context.attributes['src']?.startsWith('https:') ?? false));
    }

    testImgSrcMatcher(
      "matches a full http uri",
      matcher,
      imgSrc: 'http://legacy.http/uri.png',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "matches a full https uri",
      matcher,
      imgSrc: 'https://proper.https/uri',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "matches http: schema without path",
      matcher,
      imgSrc: 'http:',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "matches https: schema without path",
      matcher,
      imgSrc: 'http:',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "doesn't match null",
      matcher,
      imgSrc: null,
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match empty",
      matcher,
      imgSrc: '',
      shouldMatch: false,
    );
  });
  group("custom network source matcher", () {
    //TODO replace when ImageMatcherExtension is written
    matcher(ExtensionContext context) {
      return context.elementName == "img" &&
          (context.attributes['src']?.startsWith("https://www.google.com") ??
              false) &&
          (context.attributes['src']?.endsWith('.png') ?? false);
    }

    testImgSrcMatcher(
      "matches schema, domain and extension",
      matcher,
      imgSrc:
          'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "doesn't match if schema is different",
      matcher,
      imgSrc:
          'http://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png',
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match if domain is different",
      matcher,
      imgSrc:
          'https://google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png',
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match if file extension is different",
      matcher,
      imgSrc:
          'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dppng',
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match null",
      matcher,
      imgSrc: null,
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match empty",
      matcher,
      imgSrc: '',
      shouldMatch: false,
    );
  });
  group("default (base64) image data uri matcher", () {
    //TODO replace when ImageMatcherExtension is written
    matcher(ExtensionContext context) {
      return context.elementName == "img" &&
          ImageBuiltIn.dataUriFormat
                  .firstMatch(context.attributes['src'] ?? "") !=
              null;
    }

    testImgSrcMatcher(
      "matches a full png base64 data uri",
      matcher,
      imgSrc:
          '',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "matches a full jpeg base64 data uri",
      matcher,
      imgSrc:
          '',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "matches base64 data uri without data",
      matcher,
      imgSrc: 'data:image/png;base64,',
      shouldMatch: true,
    );
    testImgSrcMatcher(
      "doesn't match non-base64 image data uri",
      matcher,
      imgSrc:
          'data:image/png;hex,89504e470d0a1a0a0000000d49484452000000050000000508060000008d6f26e50000001c4944415408d763f8ffff3fc37f062005c3201284d031f18258cd04000ef535cbd18e0e1f0000000049454e44ae426082',
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match base64 non-image data uri",
      matcher,
      imgSrc: 'data:text/plain;base64,',
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't non-data schema",
      matcher,
      imgSrc: 'http:',
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match null",
      matcher,
      imgSrc: null,
      shouldMatch: false,
    );
    testImgSrcMatcher(
      "doesn't match empty",
      matcher,
      imgSrc: '',
      shouldMatch: false,
    );
  });
}

String _fakeElement(String? src) {
  return """
      <img alt ='' src="$src" />
    """;
}

@isTest
void testImgSrcMatcher(
  String name,
  bool Function(ExtensionContext) matcher, {
  required String? imgSrc,
  required bool shouldMatch,
}) {
  testWidgets(name, (WidgetTester tester) async {
    await tester.pumpWidget(
      TestApp(
        Html(
          data: _fakeElement(imgSrc),
          extensions: [
            MatcherExtension(
              matcher: matcher,
              builder: (_) => const Text("Success"),
            ),
          ],
        ),
      ),
    );
    await expectLater(
      find.text("Success"),
      shouldMatch ? findsOneWidget : findsNothing,
    );
  });
}
